package com.bittech.everything.core;

import com.bittech.everything.config.EverythingConfig;
import com.bittech.everything.core.dao.DataSourceFactory;
import com.bittech.everything.core.dao.FileIndexDao;
import com.bittech.everything.core.dao.impl.DatabaseFileIndexDao;
import com.bittech.everything.core.index.FileScan;
import com.bittech.everything.core.index.impl.FileScanImpl;
import com.bittech.everything.core.interceptor.impl.FileIndexInterceptor;
import com.bittech.everything.core.monitor.FileWatcher;
import com.bittech.everything.core.interceptor.impl.ThingClearInterceptor;
import com.bittech.everything.core.model.Condition;
import com.bittech.everything.core.model.Thing;
import com.bittech.everything.core.monitor.impl.FileWatcherImpl;
import com.bittech.everything.core.search.FileSearch;
import com.bittech.everything.core.search.impl.FileSearchImpl;

import javax.sql.DataSource;
import java.nio.file.Paths;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

/**
 * Author: secondriver
 * Created: 2018/9/26
 */
public class EverythingManager {
    
    private ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);
    
    private static volatile EverythingManager manager;
    
    private final FileScan fileScan;
    
    private final FileSearch fileSearch;
    
    private final FileWatcher fileWatcher;
    
    private final ThingClearInterceptor thingClearInterceptor;
    
    private EverythingManager() {
        //0.配置
        final EverythingConfig config = EverythingConfig.getInstance();
        
        //1.初始化数据源
        DataSource dataSource = DataSourceFactory.dataSource(config);
        
        //2.准备数据处理组件
        FileIndexDao fileIndexDao = new DatabaseFileIndexDao(dataSource);
        
        //3.检索组件
        this.fileSearch = new FileSearchImpl(fileIndexDao);
        
        //4.索引组件
        this.fileScan = new FileScanImpl();
        fileScan.interceptor(new FileIndexInterceptor(fileIndexDao));
        
        //5.文件监控组件
        this.fileWatcher = new FileWatcherImpl(fileScan, fileIndexDao, 10000);//单位：毫秒
        this.fileWatcher.monitor(EverythingConfig.getInstance().getHandlerPath());
        
        //6.后台清理组件
        this.thingClearInterceptor = new ThingClearInterceptor(fileIndexDao);
        
    }
    
    
    public static EverythingManager getInstance() {
        if (manager == null) {
            synchronized(EverythingManager.class) {
                if (manager == null) {
                    manager = new EverythingManager();
                }
            }
        }
        return manager;
    }
    
    /**
     * 索引
     */
    public void buildIndex() {
        EverythingConfig config = EverythingConfig.getInstance();
        CountDownLatch downLatch = new CountDownLatch(config.getIndexPaths().size());
        for (String path : config.getIndexPaths()) {
            executorService.submit(() -> {
                fileScan.index(path);
                downLatch.countDown();
            });
        }
        try {
            downLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (!executorService.isShutdown()) {
            executorService.shutdown();
        }
    }
    
    /**
     * 检索
     *
     * @param condition
     * @return
     */
    public List<Thing> search(Condition condition) {
        return fileSearch.search(condition).stream()
                .filter(thing -> {
                            boolean exist = Paths.get(thing.getPath()).toFile().exists();
                            if (!exist) {
                                this.thingClearInterceptor.applyThing(thing);
                            }
                            return exist;
                        }
                ).collect(Collectors.toList());
    }
    
    
    /**
     * 启动后台清理
     */
    public void startBackgroundClear() {
        Thread thread = new Thread(this.thingClearInterceptor);
        thread.setName("Clear-Thread");
        thread.setDaemon(true);
        thread.start();
    }
    
    
    /**
     * 启动后台监控
     */
    public void startBackgroundMonitor() {
        new Thread(fileWatcher::start).start();
    }
    
}
